//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>

#define IS_BLANK(c)     ((c) == ' ' || (c) == '\t')
#define IS_EOL(c)       ((c) == '\n' || (c) == '\r')
#define IS_EOF(c)       (s_pImage > s_pImageLimit || (c) == '\0')

static char *s_pImage, *s_pImageLimit;
static bool_t   s_bBackGround = FALSE;
static wchar_t s_wszCurrent[35];

typedef enum Token
{
    Token_Symbol = 0x01,
    Token_EndOfLine,
    Token_EndOfFile,
}Token;

Token gettoken()
{
    int n = 0;

    if (IS_EOF(*s_pImage)) return Token_EndOfFile;

    //
    // Skip blank
    //
    while (IS_BLANK(*s_pImage)) {
        s_pImage++;
        if (IS_EOF(*s_pImage)) return Token_EndOfFile;
    }

    //
    // Is end of line ?
    //
    if (IS_EOL(*s_pImage)) {
        do {
            s_pImage++;
            if (IS_EOF(*s_pImage)) return Token_EndOfFile;
        } while (IS_EOL(*s_pImage));
        return Token_EndOfLine;
    }

    //
    // That's must be a symbol
    //
    do {
        if ('&' == *s_pImage) {
            s_bBackGround = TRUE;
        }

        if (!s_bBackGround) {
            s_wszCurrent[n++] = (wchar_t)*s_pImage;
        }
        s_pImage++;
    } while (!IS_EOF(*s_pImage) && !IS_EOL(*s_pImage) && !IS_BLANK(*s_pImage));

    s_wszCurrent[n] = L'\0';
    return Token_Symbol;
}
#define Isspace(c) ((c == ' ') || (c == '\t') || (c=='\n') || (c=='\v') || \
            (c == '\r') || (c == '\f'))

unsigned long __cdecl wcstoul(const wchar_t * nptr, wchar_t ** endptr,
                int base)
{
    int total = 0;
    int digit;
    int radix;
    const wchar_t *start = nptr;
    int did_conversion = 0;
    int overflow = 0;
    int minus = 0;
    int maxdiv, maxrem;

    if (nptr == NULL) {
        if (!endptr) {
            *endptr = (wchar_t *) start;
        }
        return(0L);
    }

    while (Isspace (*nptr)) {
        nptr++;
    }

    if (*nptr == '-') {
        nptr++;
        minus = 1;
    }
    else if (*nptr == '+') {
        nptr++;
    }

    radix = base;
    if (base == 0 || base == 16) {
        /*
         * try to infer radix from the string (assume decimal).
         * accept leading 0x or 0X for base 16.
         */
        if (*nptr == '0') {
            did_conversion = 1;
            if (base == 0) {
                radix = 8; /* guess it's octal */
            }
            nptr++;   /* (but check for hex) */
            if (*nptr == 'X' || *nptr == 'x') {
                did_conversion = 0;
                nptr++;
                radix = 16;
            }
        }
    }
    if (radix == 0) {
        radix = 10;
    }

    maxdiv = ULONG_MAX / radix;
    maxrem = ULONG_MAX % radix;

    while ((digit = *nptr) != 0) {
        if (digit >= '0' && digit <= '9' && digit < ('0' + radix)) {
            digit -= '0';
        }
        else if (radix > 10) {
            if (digit >= 'a' && digit < ('a' + radix - 10)) {
                digit = digit - 'a' + 10;
            }
            else if (digit >= 'A' &&
                digit < ('A' + radix - 10)) {
                digit = digit - 'A' + 10;
            }
            else {
                break;
            }
        }
        else {
            break;
        }
        did_conversion = 1;
        if (total > maxdiv || (total == maxdiv && digit > maxrem)) {
            overflow = 1;
        }
        total = (total * radix) + digit;
        nptr++;
    }
    if (overflow) {
        if (endptr != NULL) {
            *endptr = (wchar_t *) nptr;
        }
        return(minus ? 1UL : ULONG_MAX);
    }
    if (endptr != NULL) {
        *endptr = (wchar_t *) ((did_conversion) ? (wchar_t *) nptr : start);
    }
    return(minus ? - total : total);
}

void getdriverinfo(int * pirq, int * piobase)
{
    wchar_t * endptr = NULL;

    ECode ec = GetBootModule(
            L"drv.cfg", (void **)&s_pImage, (void **)&s_pImageLimit);
    if (FAILED(ec)) {
        kprintf("Mantle Entry: can't found [drv.cfg].\n");
        return ;
    }
    gettoken();
    if (!wcscmp(s_wszCurrent, L"irq")) {
        gettoken();
        *pirq = wcstoul(s_wszCurrent, &endptr, 10);
    }
    gettoken();
    if (!wcscmp(s_wszCurrent, L"iobase")) {
        gettoken();
        *piobase = wcstoul(s_wszCurrent, &endptr, 16);
    }
    return;
}
